package com.stone.im.geteway.dispather;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class DispatcherInstanceManger {
    /**
     * 分发实例地址列表
     */
    private static List<DispatcherInstanceAddress> dispatcherInstanceAddressList= new ArrayList<DispatcherInstanceAddress>();

    static {
        dispatcherInstanceAddressList.add(new DispatcherInstanceAddress("localhost","127.0.0.1",8004));
    }

    /**
     * 单例
     */
    static class Singleton{
        static DispatcherInstanceManger instance = new DispatcherInstanceManger();
    }

    public static DispatcherInstanceManger getSingleton(){
        return Singleton.instance;
    }

    /**
     * 分发实例列表
     */
    private Map<String,DispatcherInstance> dispatcherInstances= new ConcurrentHashMap<String,DispatcherInstance>();

    /**
     * 随机选择一个分发系统实例
     * @return
     */
    public DispatcherInstance chooseDispatcherInstance(){

        ArrayList<DispatcherInstance> dispatcherInstanceList = new ArrayList<>();
        for (DispatcherInstance dispatcherInstance: dispatcherInstances.values()){
            dispatcherInstanceList.add(dispatcherInstance);
        }
        Random random = new Random();
        int index = random.nextInt(dispatcherInstanceList.size());

        return dispatcherInstanceList.get(index);
    }

    /**
     * 删除一个断开连接实例
     * @param key
     */
    public void removeDispatcher(String key){
        dispatcherInstances.remove(key);
    }

    /**
     * 初始化组件
     */
    public void init(){
        //主动跟一批分发
        for (DispatcherInstanceAddress dispatcherInstanceAddress : dispatcherInstanceAddressList){
            try {
                connectDispatcherInstance(dispatcherInstanceAddress);
            }catch (Exception e) {
                e.printStackTrace();
            }

        }
    }

    /**
     * 建立一个分发系统实例
     * @param dispatcherInstance
     */
    private void connectDispatcherInstance(DispatcherInstanceAddress dispatcherInstance) throws Exception {
        final EventLoopGroup loopGroup = new NioEventLoopGroup();

        Bootstrap client = new Bootstrap();

        client.group(loopGroup)
                .channel(NioSocketChannel.class)
                .option(ChannelOption.TCP_NODELAY,true)
                .option(ChannelOption.SO_KEEPALIVE,true)
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        socketChannel.pipeline().addLast(new DispatcherInstanceHandler());
                        ByteBuf delimiter = Unpooled.copiedBuffer("&_".getBytes());
                        socketChannel.pipeline().addLast(new DelimiterBasedFrameDecoder(4096,delimiter));
                    }
                });

        ChannelFuture channelFuture = client.connect(dispatcherInstance.getIp(), dispatcherInstance.getPost());//尝试发起连接
        channelFuture.addListener(new ChannelFutureListener() { //给异步化的请求加入监听器
            public void operationComplete(ChannelFuture channelFuture) throws Exception {
                if (channelFuture.isSuccess()){
                    DispatcherInstance instance = new DispatcherInstance((SocketChannel) channelFuture.channel());

                    SocketChannel channel = (SocketChannel) channelFuture.channel();
                    String channelId = channel.remoteAddress().getHostName() + ":" + channel.remoteAddress().getPort();

                    dispatcherInstances.put(channelId,instance);
                    System.out.println("跟分发系统完成长连接建立,地址为："+channelFuture.channel());
                }else{
                    channelFuture.channel().close();
                    loopGroup.shutdownGracefully();
                }
            }
        });
        channelFuture.sync();
    }
}
